using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using UnityEngine;
using Framework.Configuration;
using Framework.Data.Config;
using Newtonsoft.Json;

namespace Framework.Manager
{
    public class DataManager : ManagerBase<DataManager>
    {
        #region Manager通用
        private DataManager() { }
        #endregion

        protected override void OnInit()
        {
            string jsonPath = Application.dataPath + "/Resources/GameConfiguration.json";
            string json = File.ReadAllText(jsonPath);
            mGameConfiguration = JsonConvert.DeserializeObject<GameConfiguration>(json);
        }

        #region Config相关
        private Dictionary<string, IConfigContainer> mConfigContainerDictionary = new Dictionary<string, IConfigContainer>();

        /// <summary>获取配置（Id获取）</summary>
        /// <typeparam name="T">配置类型</typeparam>
        public T GetConfig<T>(string pId) where T : ConfigBase
        {
            string configName = typeof(T).Name;
            IConfigContainer configContainer = GetConfigContainer(configName);
            T config = configContainer.GetConfig<T>(pId);
            if (config == null)
                Debug.LogWarning($"Get config is null, {configName} don't exist id {pId}.");

            return config;
        }

        /// <summary>获取配置（Index获取，起始Index为0）</summary>
        /// <typeparam name="T">配置类型</typeparam>
        public T GetConfig<T>(int pIndex) where T : ConfigBase
        {
            string configName = typeof(T).Name;
            IConfigContainer configContainer = GetConfigContainer(configName);
            T config = configContainer.GetConfig<T>(pIndex);
            if (config == null)
                Debug.LogWarning($"Get config is null, {configName} don't exist index {pIndex}.");

            return config;
        }

        /// <summary>获取配置（ConfigName,Id获取）</summary>
        public IConfigBase GetConfig(string pConfigName, string pId)
        {
            IConfigContainer configContainer = GetConfigContainer(pConfigName);
            if (configContainer == null)
                return null;

            IConfigBase config = configContainer.GetConfig(pId);
            if (config == null)
                Debug.LogWarning($"Get config is null, {pConfigName} don't exist id {pId}.");

            return config;
        }

        /// <summary>获取配置（ConfigName,Index获取，起始Index为0）</summary>
        public IConfigBase GetConfig(string pConfigName, int pIndex)
        {
            IConfigContainer configContainer = GetConfigContainer(pConfigName);
            if (configContainer == null)
                return null;

            IConfigBase config = configContainer.GetConfig(pIndex);
            if (config == null)
                Debug.LogWarning($"Get config is null, {pConfigName} don't exist index {pIndex}.");

            return config;
        }

        /// <summary>获取ConfigContainer</summary>
        private IConfigContainer GetConfigContainer(string pConfigName)
        {
            IConfigContainer configContainer = null;

            try
            {
                if (!mConfigContainerDictionary.TryGetValue(pConfigName, out configContainer))
                {
                    Type configType = Type.GetType($"Game.Data.Config.{pConfigName}, Assembly-CSharp");
                    if (configType == null)
                    {
                        throw new InvalidOperationException($"Game.Data.Config.{pConfigName} is not exist");
                    }

                    Type containerType = typeof(ConfigContainer<>).MakeGenericType(configType);
                    configContainer = Activator.CreateInstance(containerType) as IConfigContainer;
                    mConfigContainerDictionary.Add(pConfigName, configContainer);
                }

                configContainer.DeserializeConfig();
            }
            catch (InvalidOperationException ex)
            {
                Debug.LogWarning(ex);
            }

            return configContainer;
        }


        /// <summary>获取配置异步（Id获取）</summary>
        /// <typeparam name="T">配置类型</typeparam>
        public async Task<T> GetConfigAsync<T>(string pId) where T : ConfigBase
        {
            string configName = typeof(T).Name;
            IConfigContainer configContainer = await GetConfigContainerAsync(configName);
            T config = configContainer.GetConfig<T>(pId);
            if (config == null)
                Debug.LogWarning($"Get config is null, {configName} don't exist key {pId}.");

            return config;
        }

        /// <summary>获取配置异步（Index获取，起始Index为0）</summary>
        /// <typeparam name="T">配置类型</typeparam>
        public async Task<T> GetConfigAsync<T>(int pIndex) where T : ConfigBase
        {
            string configName = typeof(T).Name;
            IConfigContainer configContainer = await GetConfigContainerAsync(configName);
            T config = configContainer.GetConfig(pIndex) as T;
            if (config == null)
                Debug.LogWarning($"Get config is null, {configName} don't exist index {pIndex}.");

            return config;
        }

        /// <summary>获取配置异步（ConfigName,Id获取）</summary>
        public async Task<IConfigBase> GetConfigAsync(string pConfigName, string pId)
        {
            IConfigContainer configContainer = await GetConfigContainerAsync(pConfigName);
            if (configContainer == null)
                return null;

            IConfigBase config = configContainer.GetConfig(pId);
            if (config == null)
                Debug.LogWarning($"Get config is null, {pConfigName} don't exist id {pId}.");

            return config;
        }

        /// <summary>获取配置异步（ConfigName,Index获取，起始Index为0）</summary>
        public async Task<IConfigBase> GetConfigAsync(string pConfigName, int pIndex)
        {
            IConfigContainer configContainer = await GetConfigContainerAsync(pConfigName);
            if (configContainer == null)
                return null;

            IConfigBase config = configContainer.GetConfig(pIndex);
            if (config == null)
                Debug.LogWarning($"Get config is null, {pConfigName} don't exist index {pIndex}.");

            return config;
        }

        private async Task<IConfigContainer> GetConfigContainerAsync(string pConfigName)
        {
            IConfigContainer configContainer = null;

            try
            {
                if (!mConfigContainerDictionary.TryGetValue(pConfigName, out configContainer))
                {
                    Type configType = Type.GetType($"Game.Data.Config.{pConfigName}, Assembly-CSharp");
                    if (configType == null)
                    {
                        throw new InvalidOperationException($"Game.Data.Config.{pConfigName} is not exist");
                    }

                    Type containerType = typeof(ConfigContainer<>).MakeGenericType(configType);
                    configContainer = Activator.CreateInstance(containerType) as IConfigContainer;
                    mConfigContainerDictionary.Add(pConfigName, configContainer);
                }

                await configContainer.DeserializeConfigAsync();
            }
            catch (InvalidOperationException ex)
            {
                Debug.LogWarning(ex);
            }

            return configContainer;
        }
        #endregion

        #region GameConfiguration相关
        private GameConfiguration mGameConfiguration = new GameConfiguration();

        public GameConfiguration GameConfiguration { get { return mGameConfiguration; } }
        #endregion

        #region PlayerPrefs相关
        public void SetPlayerPrefs<T>(string pKey, T pValue)
        {
            if (typeof(T) == typeof(int))
            {
                PlayerPrefs.SetInt(pKey, (int)(object)pValue);
            }
            else if (typeof(T) == typeof(float))
            {
                PlayerPrefs.SetFloat(pKey, (float)(object)pValue);
            }
            else if (typeof(T) == typeof(string))
            {
                PlayerPrefs.SetString(pKey, (string)(object)pValue);
            }
            else if (typeof(T) == typeof(bool))
            {
                bool b = (bool)(object)pValue;
                int value = b ? 1 : 0;
                PlayerPrefs.SetInt(pKey, value);
            }
            else
            {
                Debug.LogWarning($"SetPlayerPrefs T type is error. T type can't is {typeof(T)}");
            }
        }

        public T GetPlayerPrefs<T>(string pKey, T pDefault = default)
        {
            if (typeof(T) == typeof(int))
            {
                int value = PlayerPrefs.GetInt(pKey, (int)(object)pDefault);
                return (T)(object)value;
            }
            else if (typeof(T) == typeof(float))
            {
                float value = PlayerPrefs.GetFloat(pKey, (float)(object)pDefault);
                return (T)(object)value;
            }
            else if (typeof(T) == typeof(string))
            {
                string value = PlayerPrefs.GetString(pKey, (string)(object)pDefault);
                return (T)(object)value;
            }
            else if (typeof(T) == typeof(bool))
            {
                bool value = (bool)(object)pDefault;
                if (PlayerPrefs.HasKey(pKey))
                {
                    value = PlayerPrefs.GetInt(pKey) == 1 ? true : false;
                }
                return (T)(object)value;
            }
            else
            {
                Debug.LogWarning($"GetPlayerPrefs T type is error. T type can't is {typeof(T)}");
                return default;
            }
        }
        #endregion
    }
}